#include<mutex>
#include<condition_variable>
#include<thread>
#include<iostream>
#include<vector>
using namespace std;

class ReadWriteLock {
private:
	int readWaiting = 0;
	int writeWaiting = 0;
	int reading = 0;
	int writing = 0;
	mutex mx;
	condition_variable cond;
	bool preferWriter;
public:
	ReadWriteLock(bool isPreferWriter=false) :preferWriter(isPreferWriter) {}

	void readLock() {
		unique_lock<mutex>lock(mx);
		++readWaiting;
		cond.wait(lock, [&]() {return writing <= 0 && (!preferWriter || writeWaiting <= 0); });
		++reading;
		--readWaiting;
	}

	void writeLock() {
		unique_lock<mutex>lock(mx);
		++writeWaiting;
		cond.wait(lock, [&]() {return reading <= 0 && writing<=0; });
		++writing;
		--writeWaiting;
	}

	void readUnLock() {
		unique_lock<mutex>lock(mx);
		--reading;
		if (reading <= 0)
			cond.notify_one();
	}

	void writeUnLock() {
		unique_lock<mutex>lock(mx);
		--writing;
		cond.notify_all();
	}
};

ReadWriteLock readWriteLock(true);

void reader() {
	readWriteLock.readLock();
	cout << "reader" << endl;
	this_thread::sleep_for(std::chrono::seconds(5));
	readWriteLock.readUnLock();
}

void writer() {
	readWriteLock.writeLock();
	cout << "writer" << endl;
	this_thread::sleep_for(std::chrono::seconds(5));
	readWriteLock.writeUnLock();
}

int main() {
	vector<thread*>vec;
	for (int i = 0; i < 3; ++i) {
		vec.push_back(new thread(reader));
		vec.push_back(new thread(writer));
	}
	for (int i = 0; i < vec.size(); ++i) {
		vec[i]->join();
	}
}